/*
* Copyright (C) 2010 Jan Pokorsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.incad.kramerius.editor.server;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import cz.incad.kramerius.FedoraAccess;
import cz.incad.kramerius.KrameriusModels;
import cz.incad.kramerius.editor.server.utils.ApiUtilsHelp;
import cz.incad.kramerius.editor.share.GWTKrameriusObject.Kind;
import cz.incad.kramerius.editor.share.rpc.GetKrameriusObjectQuery;
import cz.incad.kramerius.editor.share.rpc.GetKrameriusObjectResult;
import cz.incad.kramerius.editor.share.rpc.GetKrameriusObjectResult.Descriptor;
import cz.incad.kramerius.relation.Relation;
import cz.incad.kramerius.relation.RelationModel;
import cz.incad.kramerius.relation.RelationService;
import cz.incad.kramerius.utils.StringUtils;
import cz.incad.kramerius.utils.conf.KConfiguration;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.LocaleUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.ActionException;
import net.customware.gwt.dispatch.shared.DispatchException;
/**
*
* @author Jan Pokorsky
*/
public final class GetKrameriusObjectQueryHandler implements ActionHandler<GetKrameriusObjectQuery, GetKrameriusObjectResult> {
private RelationService relationsDAO;
private FedoraAccess fedoraAccess;
private RemoteServices remotes;
private Provider<HttpServletRequest> requestProvider;
@Inject
public GetKrameriusObjectQueryHandler(
RelationService dao,
RemoteServices remotes,
@Named("rawFedoraAccess") FedoraAccess fedoraAccess, Provider<HttpServletRequest> reqProvider) {
this.relationsDAO = dao;
this.fedoraAccess = fedoraAccess;
this.remotes = remotes;
this.requestProvider = reqProvider;
}
@Override
public Class<GetKrameriusObjectQuery> getActionType() {
return GetKrameriusObjectQuery.class;
}
@Override
public GetKrameriusObjectResult execute(GetKrameriusObjectQuery action, ExecutionContext context) throws DispatchException {
String pidTxt = action.getPID();
pidTxt = EditorServerUtils.validatePID(pidTxt);
RelationModel fetchedRelations;
try {
fetchedRelations = fetchRelations(pidTxt);
} catch (IOException ex) {
// XXX implement better error handling to notify client what is wrong
Logger.getLogger(GetKrameriusObjectQueryHandler.class.getName()).log(Level.SEVERE, null, ex);
throw new ActionException(ex);
}
String loc = action.getLocale();
Map<String, Map<String,String>> fetchedProperties = fetchTitles(pidTxt, fetchedRelations, loc);
GetKrameriusObjectResult result = buildResult(pidTxt, fetchedRelations, fetchedProperties);
return result;
}
@Override
public void rollback(GetKrameriusObjectQuery action, GetKrameriusObjectResult result, ExecutionContext context) throws DispatchException {
throw new UnsupportedOperationException("Not supported.");
}
private GetKrameriusObjectResult buildResult(
String pid, RelationModel rels, Map<String, Map<String,String>> properties) {
Descriptor objDescriptor = new Descriptor(pid, properties.get(pid));
Kind objKind = EditorServerUtils.resolveKind(rels.getKind());
RelationResult relResult = buildRelationsResult(rels, properties);
GetKrameriusObjectResult result = new GetKrameriusObjectResult(
objDescriptor, objKind, relResult.relKinds, relResult.relDescriptors);
return result;
}
private RelationResult buildRelationsResult(RelationModel rels, Map<String, Map<String,String>> properties) {
Kind[] relKinds = new Kind[rels.getRelationKinds().size()];
Descriptor[][] relDescriptors = new Descriptor[relKinds.length][];
int kindIdx = 0;
for (KrameriusModels relationKind : rels.getRelationKinds()) {
List<Relation> kindRelations = rels.getRelations(relationKind);
Descriptor[] kindRelationDesriptors = new Descriptor[kindRelations.size()];
relDescriptors[kindIdx] = kindRelationDesriptors;
relKinds[kindIdx] = EditorServerUtils.resolveKind(relationKind);
++kindIdx;
int relIdx = 0;
for (Relation relation : kindRelations) {
String pid = relation.getPID();
Map<String, String> relProps = properties.get(pid);
kindRelationDesriptors[relIdx++] = new Descriptor(
relation.getPID(), relProps);
}
}
// result.setRelations(relKinds, relDescriptors);
return new RelationResult(relKinds, relDescriptors);
}
/** helper class to pass complex result */
private static final class RelationResult {
Kind[] relKinds;
Descriptor[][] relDescriptors;
public RelationResult(Kind[] relKinds, Descriptor[][] relDescriptors) {
this.relKinds = relKinds;
this.relDescriptors = relDescriptors;
}
}
private RelationModel fetchRelations(String pid) throws IOException {
RelationModel rels = relationsDAO.load(pid);
return rels;
}
private Map<String, Map<String,String>> fetchTitles(String pid, RelationModel rels, String locale) throws ActionException {
try {
Map<String, Map<String, String>> result = new HashMap<String, Map<String,String>>();
Locale loc = LocaleUtils.toLocale(locale);
if (loc == null) {
loc = Locale.getDefault();
}
JSONObject jsonObj = ApiUtilsHelp.item(pid);
String constructedTitle = ApiUtilsHelp.constructTitle(jsonObj, loc);
Map<String, JSONObject> objects = new HashMap<String, JSONObject>();
JSONArray jsonArr = ApiUtilsHelp.children(pid);
for (int i = 0, ll = jsonArr.length(); i < ll; i++) {
JSONObject chJSON = (JSONObject) jsonArr.get(i);
objects.put(chJSON.getString("pid"), chJSON);
}
result.put(pid, propertiesJSONObject(jsonObj, constructedTitle));
for (KrameriusModels relationKind : rels.getRelationKinds()) {
for (Relation relation : rels.getRelations(relationKind)) {
JSONObject jsonObject = objects.get(relation.getPID());
if (jsonObject != null) {
result.put(relation.getPID(), propertiesJSONObject(jsonObject, constructedTitle));
}
}
}
return result;
} catch (JSONException e) {
throw new ActionException(e);
}
}
public static Map<String, String> propertiesJSONObject(JSONObject jsonObj, String constructedTitle) throws JSONException {
Map<String, String> map = new HashMap<String, String>();
map.put("title", jsonObj.getString("title"));
map.put("pid", jsonObj.getString("pid"));
map.put("policy", jsonObj.getString("policy"));
map.put("rootTitle", jsonObj.getString("root_title"));
map.put("constructedTitle", constructedTitle);
String model = jsonObj.getString("model");
map.put("model", model);
if (jsonObj.has("details")) {
JSONObject detailsJSON = jsonObj.getJSONObject("details");
PropertiesFromModels detail = PropertiesFromModels.findDetail(model);
if (detail != null) {
detail.details(map, detailsJSON);
}
}
if (jsonObj.has("context")) {
JSONArray jsonArray = jsonObj.getJSONArray("context");
if (jsonArray.length() > 0) {
StringBuilder builder = new StringBuilder();
JSONArray selArr = jsonArray.getJSONArray(0);
for (int i = 0,ll=selArr.length(); i < ll; i++) {
if (i > 0) builder.append(",");
JSONObject value = selArr.getJSONObject(i);
builder.append(value.getString("pid"));
}
map.put("context", builder.toString());
}
}
return map;
}
private String title(String pid) throws JSONException {
String url = KConfiguration.getInstance().getConfiguration().getString("api.point")+"/item/"+pid;
Logger.getLogger(GetKrameriusObjectQueryHandler.class.getName()).log(Level.INFO, "URL + "+url);
JSONObject jsonObject = ApiUtilsHelp.getJSONasObject(url);
String rtitle = jsonObject.getString("root_title");
String obj = jsonObject.getString("title");
String title = obj;
if (StringUtils.isAnyString(rtitle)) {
title = rtitle+" " +obj;
}
Logger.getLogger(GetKrameriusObjectQueryHandler.class.getName()).log(Level.INFO, "Title "+title);
return title;
}
private String fetchDCName(String pid) throws ActionException {
try {
return remotes.fetchDCName(pid);
} catch (IOException ex) {
Logger.getLogger(GetKrameriusObjectQueryHandler.class.getName()).log(Level.SEVERE, "pid: " + pid, ex);
throw new ActionException("The server is out of order.");
}
}
private static enum PropertiesFromModels {
page {
@Override
public void details(Map<String, String> map, JSONObject jsonObject) throws JSONException {
List<String> alist = new ArrayList<String>();
String title = map.get("title");
if (jsonObject.has("pagenumber")) {
String jsonObjTitle = jsonObject.getString("pagenumber");
if (jsonObjTitle != null) {
jsonObjTitle = jsonObjTitle.trim();
if ((title != null) && (!jsonObjTitle.equals(title))) {
alist.add(jsonObjTitle);
}
}
}
if (jsonObject.has("type")) {
String type = jsonObject.getString("type");
type = type.trim();
alist.add(type);
}
if (!alist.isEmpty()) {
map.put("details", alist.toString());
}
}
},
periodicalitem {
@Override
public void details(Map<String, String> map, JSONObject jsonObject) throws JSONException {
List<String> alist = new ArrayList<String>();
if (jsonObject.has("issueNumber")){
String issueNumber = jsonObject.getString("issueNumber");
if (issueNumber != null) {
issueNumber = issueNumber.trim();
if (!issueNumber.equals("")) {
alist.add(issueNumber);
//map.put("issueNumber", issueNumber);
}
}
}
if (jsonObject.has("date")){
String date = jsonObject.getString("date");
if (date != null) {
date = date.trim();
if (!date.equals("")) {
alist.add(date);
//map.put("date", date);
}
}
}
if (jsonObject.has("partNumber")){
String partNumber = jsonObject.getString("partNumber");
if (partNumber != null) {
partNumber = partNumber.trim();
if (!partNumber.equals("")) {
alist.add(partNumber);
//map.put("partNumber", partNumber);
}
}
}
if (!alist.isEmpty()) {
map.put("details", alist.toString());
}
}
},
periodicalvolume {
@Override
public void details(Map<String, String> map, JSONObject jsonObject) throws JSONException {
if (jsonObject.has("year")){
String year = jsonObject.getString("year");
if (year != null) {
year = year.trim();
if (!year.equals("")) {
map.put("details", Arrays.asList(year).toString());
}
}
}
}
};
public abstract void details(Map<String, String> map, JSONObject jsonObject) throws JSONException;
public static PropertiesFromModels findDetail(String model) {
PropertiesFromModels[] values = PropertiesFromModels.values();
for (PropertiesFromModels detail : values) {
if (detail.name().equals(model)) {
return detail;
}
}
return null;
}
}
}